home *** CD-ROM | disk | FTP | other *** search
- ;─────────────────────────────────────────────────────────────────────────────
- ; The ULTImate MUTation Engine .93ß (c) 1993 Black Wolf Enterprises
- ; pardon the title, had to think of something... }-)
- ;
- ;ULTIMUTE is a mutation engine written for security-type applications and
- ;other areas where mutation of executable code is necessary. For my personal
- ;use, I have implemented it in Black Wolf's File Protection Utilities 2.1s,
- ;using it to encrypt the code placed onto EXE's and COM's to protect them
- ;from simple modification and/or unauthorized use. The encryption algorithms
- ;themselves are terribly simple - the main point being that they change
- ;each time and are difficult to trace through. This engine is written mainly
- ;to keep a "hack one, hack 'em all" approach from working on protected code,
- ;rather than to keep the code secure by a cryptologist's point of view.
- ;
- ;Including: Better Anti-Tracing abilities, 1017 byte size, Anti-Disassembling
- ; code, largely variable size for decoder. Also includes variable
- ; calling segmentation (i.e. CS<>ES<>DS, and can be called via
- ; near call, far call, or interrupt, the last of which can be
- ; useful as a memory-resident handler for multiple programs to
- ; use).
- ;
- ;Note: Please - this program and it's source have been released as freeware,
- ; but do NOT use the mutation engine in viruses! For one thing, the
- ; decryptor sequence has several repetitive sequences that can be scanned
- ; for, and for another, that just isn't what it was designed for and
- ; I would NOT appreciate it. If you MUST use someone else's mutation
- ; engine for such, use the TPE or MTE. I do NOT condone such, however.
- ;
- ;Any modifications made to this program should be listed below the solid line,
- ;along with the name of the programmer and the date the file was changed.
- ;Also - they should be commented where changed. If at all possible, report
- ;modifications to file to the address listed in the documentation.
- ;
- ;DISCLAIMER: The author takes ABSOLUTELY NO RESPONSIBILITY for any damages
- ;resulting from the use/misuse of this program. The user agrees to hold
- ;the author harmless for any consequences that may occur directly or
- ;indirectly from the use of this program by utilizing this program/file
- ;in any manner. Please use the engine with care.
- ;─────────────────────────────────────────────────────────────────────────────
- ;Modifications:
- ; None as of yet (original release version)
-
- .model tiny
- .radix 16
- .code
-
- public _ULTMUTE, _END_ULTMUTE, Get_Rand, Init_Rand
-
- ;Underscores are used so that these routines can be called from C and other
- ;upper level languages. If you wish to use Get_Rand and Init_Rand in C, you
- ;need to add underscores in their names as well. Also, the random number
- ;generations may not be sound for all purposes. They do the job for this
- ;program, but they may/may not be mathematically correct.
-
- ;─────────────────────────────────────────────────────────────────────────────
- ;ENTRY:
- ; CX=Code Length BX=New_Entry_Point
- ; DS:SI=Code AX=Calling Style
- ; ES:DI=Destination 1=Near Call, 2=Far Call, 3=Int Call
- ;
- ;RETURN:
- ; CX=New Size ES:DI = Same, now contains encrypted code
- ; w/decryptor
- ;─────────────────────────────────────────────────────────────────────────────
- _ULTMUTE:
- push bp ax bx cx dx es ds si di
- call Get_Our_Offset
- Offset_Mark:
- inc cx
- inc cx
- mov word ptr cs:[bp+1+Set_Size],cx
- mov word ptr cs:[Start_Pos+bp],bx
- call Init_Rand
- call Get_Base_Reg
- call Setup_Choices
- call Create_EncDec
- call Copy_Decrypt_Code
- call Encrypt_It
- Ending_ULTMUTE:
- pop di si ds es dx cx bx ax
- add cx,cs:[Decryptor_Length+bp]
- inc cx
- inc cx
- pop bp
- cmp ax,3 ;Select Returning method, i.e. retn, retf, iret
- je Int_Call
- cmp ax,2
- je Far_Call
- Near_Call:
- retn
- Far_Call:
- retf
- Int_Call:
- iret
- ;─────────────────────────────────────────────────────────────────────────────
- Get_Our_Offset:
- mov bp,sp
- mov bp,ss:[bp] ;This trick finds our current offset
- sub bp,offset Offset_Mark ;from the compiling point, as it
- ret ;is usually not constant....
- ;─────────────────────────────────────────────────────────────────────────────
- Init_Rand:
- push ax ds
- xor ax,ax
- mov ds,ax
- mov ax,ds:[46c] ;Get seed from timer click at
- pop ds ;0000:046c
- mov cs:[rand_seed+bp],ax
- pop ax
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Get_Rand:
- push cx dx
- mov ax,cs:[rand_seed+bp]
- mov cx,0deadh
- mul cx ;This probably isn't a good algorithm,
- xor ax,0dada ;(understatement) but it works for
- ror ax,1 ;our purposes in this application.
- mov cs:[rand_seed+bp],ax
- pop dx cx
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- rand_seed dw 0
- Base_Reg db 0
- Base_Pointer db 0
- Start_Pos dw 0
- ;─────────────────────────────────────────────────────────────────────────────
- Get_Base_Reg:
- call Get_Rand
- and ax,11b
- cmp al,1 ;Eliminate CX for loop purposes
- je Get_Base_Reg
- mov byte ptr cs:[bp+Base_Reg],al
- Do_Pointer_Reg:
- call Get_Rand
- shr al,1
- jc Done_Base_Reg
- mov byte ptr cs:[bp+Base_Pointer],0
- ret
- Done_Base_Reg:
- mov byte ptr cs:[bp+Base_Pointer],1
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Setup_Choices:
- push ds si
- push cs
- pop ds
- mov si,bp
-
- call Get_Rand
- mov word ptr [si+Xor_It+2],ax ;Randomize Xor
- call Get_Rand
- mov word ptr [si+Dummy3+2],ax ;Randomize Add/Sub
- mov word ptr [si+Dummy7+2],ax
-
- call Get_Rand ;Randomize Add/Sub
- mov word ptr [si+Dummy4+2],ax
- mov word ptr [si+Dummy8+2],ax
-
- call Get_Rand
- mov byte ptr [si+Rand_Byte1],al ;Randomize Random bytes
- mov byte ptr [si+Rand_Byte2],ah
- call Get_Rand
- mov byte ptr [si+Rand_Byte3],al
- mov byte ptr [si+Rand_Byte4],ah
- call Get_Rand
- mov byte ptr [si+Rand_Byte5],al
- mov byte ptr [si+Rand_Byte6],ah
- call Get_Rand
- mov byte ptr [si+Rand_Byte7],al
- mov byte ptr [si+Rand_Byte8],ah
- call Get_Rand
- mov byte ptr [si+Rand_Byte9],al
- mov byte ptr [si+Rand_Byte10],ah
-
- mov al,byte ptr [si+Base_Reg]
- Set_Switcher:
- and byte ptr [si+Switcher+1],0e6 ;Delete Register
- mov ah,al
- shl ah,1
- shl ah,1
- shl ah,1
- or byte ptr [Switcher+1+si],ah
- Set_Switcher_Pointer:
- push ax
- mov al,byte ptr [si+Base_Pointer]
- or byte ptr [si+Switcher+1],al
- Set_Set_Pointy:
- and byte ptr [si+Set_Pointy],0fe
- or byte ptr [si+Set_Pointy],al
- and byte ptr [si+Inc_Pointy],0fe
- or byte ptr [si+Inc_Pointy],al
- and byte ptr [si+Inc_Pointy+1],0fe
- or byte ptr [si+Inc_Pointy+1],al
- pop ax
- Set_Xorit:
- and byte ptr [si+Xor_It+1],0fc
- or byte ptr [si+Xor_It+1],al
- Set_Flip_It:
- and byte ptr [si+Flip_It+1],0e4
- or byte ptr [si+Flip_It+1],al
- or byte ptr [si+Flip_It+1],ah
- Set_Rotate_It:
- and byte ptr [si+do_rotate+1],0fc
- or byte ptr [si+do_rotate+1],al
- and byte ptr [si+do_rot2+1],0fc
- or byte ptr [si+do_rot2+1],al
- Set_IncDec:
- and byte ptr [si+inc_bx_com],0fc
- or byte ptr [si+inc_bx_com],al
- and byte ptr [si+dec_bx_com],0fc
- or byte ptr [si+dec_bx_com],al
-
- and byte ptr [si+Dummy5],0fc
- or byte ptr [si+Dummy5],al
- and byte ptr [si+Dummy6],0fc
- or byte ptr [si+Dummy6],al
-
- Set_AddSub:
- and byte ptr [si+Dummy3+1],0fc
- and byte ptr [si+Dummy4+1],0fc
- or byte ptr [si+Dummy3+1],al
- or byte ptr [si+Dummy4+1],al
-
- and byte ptr [si+Dummy7+1],0fc
- and byte ptr [si+Dummy8+1],0fc
- or byte ptr [si+Dummy7+1],al
- or byte ptr [si+Dummy8+1],al
- pop si ds
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Create_EncDec:
- push es di cx
- push cs
- pop es
- lea di,[bp+Encrypt_Sequence]
- call Get_Rand
- and ax,1fh
- shr ax,1 ;Insure odd number of encryptors to prevent
- shl ax,1 ;things like "INC AX / DEC AX" to leave prog
- inc ax ;unencrypted.
-
- mov byte ptr cs:[bp+Encrypt_Length],al
- xchg cx,ax
- Make_Pattern:
- call Get_Rand
- and ax,7
- stosb
- loop Make_Pattern
- pop cx di es
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Copy_Decrypt_Code:
- push si di bx cx ds
- push bx di ;save for loop
-
- push cs
- pop ds
-
- lea si,[bp+Set_Pointy]
- movsw
- movsb
- lodsb ;Copy initial encryptor
- movsw
- movsb
- lodsb
- movsw
-
- mov cl,byte ptr cs:[bp+Encrypt_Length]
- xor ch,ch
- lea si,[Encrypt_Sequence+bp] ;didn't have bp earlier
- Dec_Set_Loop:
- push cx
- lodsb
- push si ;Create the Decryptor from Sequence
-
- mov bl,al
- xor bh,bh
- shl bx,1
- add bx,bp
- add bx,offset Command_Table
- mov ax,cs:[bx]
-
- mov cl,ah
- xor ah,ah
-
- lea si,[Xor_It+bp]
- add si,ax
- repnz movsb
-
- pop si
- pop cx
- loop Dec_Set_Loop
-
-
- lea si,[Switcher+bp]
- movsw
- lodsb ;Finish off Decryptor
- movsw
- lodsb
-
- movsw ;Loop Setup
- movsw
-
- pop si bx
- mov ax,di ;Set Loop
- sub ax,si ;Do size of loop and offset from loop
-
- mov cs:[Decryptor_Length+bp],ax
-
- push ax ;Changed for Jump
- not ax
- add ax,5
- stosw
- pop ax
-
- add bx,ax ;Set initial Pointer
- mov es:[si+1],bx
-
- mov ax,di
- pop ds cx bx di si
- push si di bx cx
- Copy_Prog:
- push ax
- sub ax,di
- add ax,bx
- mov word ptr es:[di+1],ax
- pop ax
- mov di,ax
- repnz movsb
- pop cx bx di si
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Encrypt_It:
- push bx cx di si
-
- call set_seqp
-
- mov ax,cs:[Decryptor_Length+bp]
- inc ax
- inc ax
- add di,ax ;DI=start of code to be encrypted
- ;CX=Length of code to encrypt
- mov si,di
- push es
- pop ds
- Big_Enc_Loop:
- push cx
- call Switcher
- mov cx,cs:[Encrypt_Length+bp]
-
- Encrypt_Value:
- push ax bx cx dx si di
- mov si,cs:[Save_SI+bp]
- dec si
- mov bl,cs:[si] ;??
- mov cs:[Save_SI+bp],si
- lea si,cs:[Com_Table_2+bp]
- xor bh,bh
- shl bx,1
- add si,bx
- mov bx,cs:[si]
- add bx,bp
- mov word ptr cs:[Next_Command+bp],bx
- pop di si dx cx bx ax
- call cs:[Next_Command+bp]
- Loop Encrypt_Value
-
- pop cx
- call Switcher
- call Inc_Pointy
- call set_seqp
- loop Big_Enc_Loop
- pop si di cx bx
- ret
-
- Save_SI dw 0
- Next_Command dw 0
- set_seqp:
- push si
- lea si,cs:[Encrypt_Sequence+bp] ;SI=Encrypt_Sequence
- add si,cs:[Encrypt_Length+bp] ;SI=End of Encrypt Sequence
- mov cs:[Save_SI+bp],SI
- pop si
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Command_Table: ;8 commands -> 3 bits.
- db [Xor_It-Xor_It],(Flip_It-Xor_It-1)
- db [Flip_It-Xor_It],(Rotate_It_1-Flip_It-1)
- db [Rotate_It_1-Xor_It],(Rotate_It_2-Rotate_It_1-1)
- db [Rotate_It_2-Xor_It],(Dummy1-Rotate_It_2-1)
- db [Dummy1-Xor_It],(Dummy2-Dummy1-1)
- db [Dummy2-Xor_It],(Dummy3-Dummy2-1)
- db [Dummy3-Xor_It],(Dummy4-Dummy3-1)
- db [Dummy4-Xor_It],(Dummy5-Dummy4-1)
- Com_Table_2:
- dw [offset Xor_It]
- dw [offset Flip_It]
- dw [offset Rotate_It_2]
- dw [offset Rotate_It_1]
- dw [offset Dummy5]
- dw [offset Dummy6]
- dw [offset Dummy7]
- dw [offset Dummy8]
- ;─────────────────────────────────────────────────────────────────────────────
- Set_Pointy:
- mov di,1234 ;Pointer to Code
- ret
- Set_Size:
- mov cx,1234 ;Size
- ret
- Switcher:
- xchg bx,[di]
- ret
- Inc_Pointy:
- inc di
- inc di
- ret
-
- Loop_Mut:
- dec cx
- jz End_Loop_Mut
- loop_set:
- jmp _ULTMUTE
- End_Loop_Mut:
- ret
- Xor_It:
- xor bx,1234
- ret
- Flip_It:
- xchg bh,bl
- ret
-
- Rotate_It_1:
- jmp before_rot
- do_rotate:
- ror bx,1
- jmp after_rot
- before_rot:
- push ax
- call Ports1
- pop ax
- jmp do_rotate
- Ports1:
- in al,21
- or al,02
- out 21,al
- ret
-
- Ports2:
- in al,21
- xor al,02
- out 21,al
- ret
- after_rot:
- push ax
- call ports2
- pop ax
- ret
-
- Rotate_It_2:
- cli
- jmp confuzzled1
- do_rot2:
- rol bx,1
- call Switch_Int_1_3
- jmp donerot2
-
- confuzzled1:
- call Switch_Int_1_3
- jmp do_rot2
-
- Switch_Int_1_3:
- push ax ds
- xor ax,ax
- mov ds,ax
- jmp short exch1
- db 0eah
- exch1:
- xchg ax,word ptr ds:[4]
- jmp short exch2
- db 9ah
- exch2:
- xchg ax,word ptr ds:[0c]
- xchg ax,word ptr ds:[4]
- pop ds ax
- ret
- donerot2:
- ret
-
- Dummy1:
- jmp short inc_bx_com ;Kill Disassemblers
- db 0ea
- Rand_Byte1:
- db 0ea
- inc_bx_com:
- inc bx
- ret
- Dummy2:
- jmp short Kill_1
- Rand_Byte2:
- db 0ea
- Cont_Kill1:
- cli
- xchg ax,ds:[84]
- xchg ax,ds:[84]
- sti
- pop ds ax
- dec_bx_com:
- dec bx
- jmp short quit_Kill1
- Kill_1:
- push ax ds
- xor ax,ax
- mov ds,ax ;Anti-Debugger (Kills Int 21)
- jmp short Cont_Kill1
- Rand_Byte3:
- db 0e8
- quit_Kill1:
- ret
- Dummy3:
- add bx,1234
- push bx
- call throw_debugger
- Rand_Byte4:
- db 0e8 ;Prefetch Trick
- into_throw:
- sub bx,offset Rand_Byte4
- add byte ptr [bx+trick_em+1],0ba
- trick_em:
- jmp short done_trick
- Rand_Byte5:
- db 0ea
- throw_debugger:
- pop bx
- jmp short into_throw
- Rand_Byte6:
- db 0ea
- done_trick:
- sub byte ptr [bx+trick_em+1],0ba
- pop bx
- ret
- Dummy4:
- sub bx,1234
- jmp short Get_IRQ
- Rand_Byte7 db 0e8
- Kill_IRQ:
- out 21,al
- xor al,2
- jmp short Restore_IRQ
- Rand_Byte8 db 0e8
- Rand_Byte9 db 0e8 ;This will kill the keyboard
- Get_IRQ: ;IRQ
- push ax
- in al,21
- xor al,2
- jmp short Kill_IRQ
- Rand_Byte10 db 0e8
- Restore_IRQ:
- out 21,al
- pop ax
- ret
-
- ;The following are used for the encryption algorithm to reverse commands that
- ;include anti-tracing.
- Dummy5:
- dec bx
- ret
- Dummy6:
- inc bx
- ret
- Dummy7:
- sub bx,1234
- ret
- Dummy8:
- add bx,1234
- ret
- ;─────────────────────────────────────────────────────────────────────────────
- Decryptor_Length dw 0
- Encrypt_Length dw 0
- Encrypt_Sequence db 30 dup(0)
- ;─────────────────────────────────────────────────────────────────────────────
- _END_ULTMUTE:
- end _ULTMUTE
-